%{
//********************************************************************************************************************//
//ORGANIZATION:
//AUTHOR: bpeng(bogers.peng@gmail.com)
//SUMMARY:
//********************************************************************************************************************//
#include "../MssqlScanner.h"
#include "System/Base/Exceptions.h"

using namespace std;
using namespace Native::System;
using namespace Native::Compiling;
using namespace Native::Compiling::Sql;
%}

%x COMMENT_SINGLE_LINE
%x COMMENT_MULTI_LINE
%x PROCEDURE_HEADER
%x PROCEDURE_HEADER_END
%x FUNCTION_DECLARATION
%x FUNCTION_DECLARATION_END

%x DECLARE_VARIABLES
%x C_PROCEDURE
%x ARGUMENTS

%option c++
%option prefix = "CMssqlScanner"
%option debug
%option noyywrap
%option yylineno
%option outfile = "MssqlScanner.lex.out"
%option case-insensitive

keyword             "ADD"|"EXISTS"|"PRECISION"|"ALL"|"EXIT"|"PRIMARY"|"ALTER"|"EXTERNAL"|"PRINT"|"AND"|"FETCH"|"PROC"|"ANY"|"FILE"|"C_PROCEDURE"|"AS"|"FILLFACTOR"|"PUBLIC"|"ASC"|"FOR"|"RAISERROR"|"AUTHORIZATION"|"FOREIGN"|"READ"|"BACKUP"|"FREETEXT"|"READTEXT"|"BEGIN"|"FREETEXTTABLE"|"RECONFIGURE"|"BETWEEN"|"FROM"|"REFERENCES"|"BREAK"|"FULL"|"REPLICATION"|"BROWSE"|"FUNCTION"|"RESTORE"|"BULK"|"GOTO"|"RESTRICT"|"BY"|"GRANT"|"RETURN"|"CASCADE"|"GROUP"|"REVERT"|"CASE"|"HAVING"|"REVOKE"|"CHECK"|"HOLDLOCK"|"RIGHT"|"CHECKPOINT"|"IDENTITY"|"ROLLBACK"|"CLOSE"|"IDENTITY_INSERT"|"ROWCOUNT"|"CLUSTERED"|"IDENTITYCOL"|"ROWGUIDCOL"|"COALESCE"|"IF"|"RULE"|"COLLATE"|"IN"|"SAVE"|"COLUMN"|"INDEX"|"SCHEMA"|"COMMIT"|"INNER"|"SECURITYAUDIT"|"COMPUTE"|"INSERT"|"SELECT"|"CONSTRAINT"|"INTERSECT"|"SESSION_USER"|"CONTAINS"|"INTO"|"SET"|"CONTAINSTABLE"|"IS"|"SETUSER"|"CONTINUE"|"JOIN"|"SHUTDOWN"|"CONVERT"|"KEY"|"SOME"|"CREATE"|"KILL"|"STATISTICS"|"CROSS"|"LEFT"|"SYSTEM_USER"|"CURRENT"|"LIKE"|"TABLE"|"CURRENT_DATE"|"LINENO"|"TABLESAMPLE"|"CURRENT_TIME"|"LOAD"|"TEXTSIZE"|"CURRENT_TIMESTAMP"|"MERGE"|"THEN"|"CURRENT_USER"|"NATIONAL"|"TO"|"CURSOR"|"NOCHECK"|"TOP"|"DATABASE"|"NONCLUSTERED"|"TRAN"|"DBCC"|"NOT"|"TRANSACTION"|"DEALLOCATE"|"NULL"|"TRIGGER"|"DECLARE"|"NULLIF"|"TRUNCATE"|"DEFAULT"|"OF"|"TSEQUAL"|"DELETE"|"OFF"|"UNION"|"DENY"|"OFFSETS"|"UNIQUE"|"DESC"|"ON"|"UNPIVOT"|"DISK"|"OPEN"|"UPDATE"|"DISTINCT"|"OPENDATASOURCE"|"UPDATETEXT"|"DISTRIBUTED"|"OPENQUERY"|"USE"|"DOUBLE"|"OPENROWSET"|"USER"|"DROP"|"OPENXML"|"VALUES"|"DUMP"|"OPTION"|"VARYING"|"ELSE"|"OR"|"VIEW"|"END"|"ORDER"|"WAITFOR"|"ERRLVL"|"OUTER"|"WHEN"|"ESCAPE"|"OVER"|"WHERE"|"EXCEPT"|"PERCENT"|"WHILE"|"EXEC"|"PIVOT"|"WITH"|"EXECUTE"|"PLAN"|"WRITETEXT"
string              "N"?\'{1}.*\'{1}
integer             [0-9]+
digit               [0-9\.]+
keyword_blank       [ \t\r\n]+
operator_blank      [ \t\r\n]*
method_name         ([_a-zA-Z\[-\]]+"."{1}[_a-zA-Z0-9\[-\]]+)|[_a-zA-Z0-9\[-\]]+
variable_name       "@"[_a-zA-Z0-9]+
variable_type       [_a-zA-z0-9]+
variable_subtype    [0-9\,]+
variable_value      "NULL"|"@"[_a-zA-Z0-9]+|"N"?\'{1}.*\'{1}|[0-9\.]+
%%

<COMMENT_MULTI_LINE>. {
    _comment.Content(StringHelper::ToWideString(yytext));
}
<COMMENT_MULTI_LINE>"*/" {
    _comment.Ending(yylineno);

    BEGIN _last_status;
}

<COMMENT_SINGLE_LINE>\n {
    _comment.Ending(yylineno);

    BEGIN _last_status;
}
<COMMENT_SINGLE_LINE>. {
    _comment.Content(StringHelper::ToWideString(yytext));
}

"CREATE"{keyword_blank}"C_PROCEDURE" {
    _stage = STAGE_PROCEDURE_DECLARATION;

    _declaration_gather.CollectStarting(yylineno);
    _declaration_gather.CollectSequence(_MakeSequence());

    _last_status = INITIAL;

    BEGIN PROCEDURE_HEADER;
}

<PROCEDURE_HEADER>"/*" {
    _last_status = PROCEDURE_HEADER;
    _BeginComment(yylineno, CComment::STYLE_MULTI);

    BEGIN COMMENT_MULTI_LINE;
}

<PROCEDURE_HEADER>"--" {
    _last_status = PROCEDURE_HEADER;
    _BeginComment(yylineno, CComment::STYLE_SINGLE);

    BEGIN COMMENT_SINGLE_LINE;
}

<PROCEDURE_HEADER>{method_name} {
    try {
        _declaration_gather.CollectName(StringHelper::ToWideString(yytext));
    } catch (CException& e) {
        NATIVE_THROW_CAUGHT(L"Run", e);
    }
}

<PROCEDURE_HEADER>"(" {
    _variable_gather.Register(&_declaration_gather);

    BEGIN DECLARE_VARIABLES;
}

<PROCEDURE_HEADER>"AS" {
}

<PROCEDURE_HEADER>. {
    ;
}

<PROCEDURE_HEADER_END>"AS" {
    /*m_oDeclaration.AppendParameter(m_oVariable);
    m_oDeclaration.EndingLine(yylineno);

    m_oVariable.Clear();

    pCapturer->CaptureDeclaration(m_oDeclaration);
    
    m_eStage = E_STAGE_BODY;*/

    BEGIN INITIAL;
}

<DECLARE_VARIABLES>"/*" {
    _last_status = DECLARE_VARIABLES;
    _BeginComment(yylineno, CComment::STYLE_MULTI);

    BEGIN COMMENT_MULTI_LINE;
}

<DECLARE_VARIABLES>"--" {
    _last_status = DECLARE_VARIABLES;
    _BeginComment(yylineno, CComment::STYLE_SINGLE);

    BEGIN COMMENT_SINGLE_LINE;
}

<DECLARE_VARIABLES>{variable_name} {
    try {
        _variable_gather.CollectStarting(yylineno);
        _variable_gather.CollectName(StringHelper::ToWideString(yytext));
        _variable_gather.CollectEnding(yylineno);
    } catch (CException& e) {
        NATIVE_THROW_CAUGHT(L"Run", e);
    }
}

<DECLARE_VARIABLES>{variable_type}|({variable_type}{operator_blank}"("{operator_blank}{variable_subtype}{operator_blank}")") {
    try {
        CString type;
        CString text(yytext);
        auto strings = text.Split(L'(');

        if (strings.size() == 1) {
            type = text;
        } else {
            type = _TrimBlank(strings[0]);
            type.Append(L'(');
            type.Append(strings[1].Substring(0, strings[1].Length()-1));
            type.Append(L')');
        }
        _variable_gather.CollectType(type);
        _variable_gather.CollectEnding(yylineno);
    } catch (CException& e) {
        NATIVE_THROW_CAUGHT(L"Run", e);
    }
}

<DECLARE_VARIABLES>"="{operator_blank}{variable_value} {
    try {
        CString value(yytext);

        _variable_gather.CollectValue(value.Substring(1));
        _variable_gather.CollectEnding(yylineno);
    } catch (CException& e) {
        NATIVE_THROW_CAUGHT(L"Run", e);
    }
}

<DECLARE_VARIABLES>{keyword_blank}"OUTPUT" {
    try {
        _variable_gather.CollectOutput(L"true");
        _variable_gather.CollectEnding(yylineno);
    } catch (CException& e) {
        NATIVE_THROW_CAUGHT(L"Run", e);
    }
}

<DECLARE_VARIABLES>"," {
    _variable_gather.Update();
    _variable_gather.Clear();
}

<DECLARE_VARIABLES>{ROperatorBlank}")" {
    try {
        _variable_gather.Update();
        _variable_gather.Clear();
    } catch (CException& e) {
        NATIVE_THROW_CAUGHT(L"Run", e);
    }

    if(STAGE_PROCEDURE_DECLARATION == _stage) {
        BEGIN PROCEDURE_HEADER_END;
    } else {
        BEGIN FUNCTION_DECLARATION_END;
    }
}

.|\n {
    ;
}

%%
namespace Native { namespace Compiling { namespace Sql
{
    CMssqlScanner::CMssqlScanner(istream* yy_in, ostream* yy_out)
        :CMssqlScannerFlexLexer(yy_in, yy_out), _sequence(0)
    {
        _status_stack.Push(INITIAL);
    }

    CMssqlScanner::~CMssqlScanner()
    {
    }

    CString CMssqlScanner::_TrimBlank(C_STRING& text)
    {
        return text.Trim(wstring(L" \t\r\n"));
    }

    int CMssqlScanner::_MakeSequence()
    {
        return ++_sequence;
    }

    void CMssqlScanner::_BeginComment(size_t line, CComment::EStyle style)
    {
        _comment.Clear();
        _comment.Style(style);
        _comment.Starting(line);
        _comment.Sequence(_MakeSequence());
    }
}}

#ifdef yylex
#undef yylex
#endif

int CMssqlScannerFlexLexer::yylex()
{
    std::cerr << "in MssqlScannerFlexLexer::yylex() !" << std::endl;
    return 0;
}

